package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.zzyl.constant.RedisConstant;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.ResourceDto;
import com.zzyl.entity.Resource;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.ResourceMapper;
import com.zzyl.service.ResourceService;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.ResourceVo;
import com.zzyl.vo.TreeItemVo;
import com.zzyl.vo.TreeVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    private ResourceMapper resourceMapper;

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_TREE,allEntries = true)
    })
    public void addResource(ResourceDto resourceDto) {
        Resource resource = new Resource();
        BeanUtils.copyProperties(resourceDto, resource);
        //查询父资源
        Resource parentResource = resourceMapper.getById(resourceDto.getParentResourceNo());
        //设置数据状态为父资源的数据状态
        resource.setDataState(parentResource.getDataState());
        //TODO 该接口业务逻辑尚未开始写
        //根据父资源编号生成资源编号
        boolean isMenu = true;
        if (resourceDto.getResourceType().equals(SuperConstant.BUTTON)) {
            isMenu = false;
        }
        String resourceNo = GenerateResourceNo(resource.getParentResourceNo(), isMenu);
        resource.setResourceNo(resourceNo);
        resourceMapper.insert(resource);
    }

    //生成资源编码
    private String GenerateResourceNo(String parentResourceNo, boolean isMenu) {
        //如果是菜单并且菜单超过三级,抛出异常
        if (isMenu && (NoProcessing.processString(parentResourceNo).length() / 3) >= 5) {
            throw new BaseException(BasicEnum.RESOURCE_DEPTH_UPPER_LIMIT);
        }
        //查询父节点下所有子节点
        List<ResourceVo> list = resourceMapper.list(Resource.builder().parentResourceNo(parentResourceNo).build());
        if (ObjectUtil.isEmpty(list)) {
            return NoProcessing.createNo(parentResourceNo, false);
        } else {
            //遍历集合获取最大的子节点
            String maxNo = list.stream().map(o -> o.getResourceNo()).max(String::compareTo).get();
            return NoProcessing.createNo(maxNo, true);
        }

    }
    @Cacheable(cacheNames = RedisConstant.RESOURCE_LIST,key="#resourceDto.hashCode()")
    @Override
    public List<ResourceVo> list(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        List<ResourceVo> res = resourceMapper.list(resource);
        return res;
    }
    @Cacheable(cacheNames = RedisConstant.RESOURCE_TREE)
    @Override
    public TreeVo tree(ResourceDto resourceDto) {
        //查询所有菜单
        Resource dto = Resource.builder().parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID)).dataState(SuperConstant.DATA_STATE_0).resourceType(SuperConstant.MENU).build();
        List<ResourceVo> list = resourceMapper.list(dto);
        //创建结果集
        ArrayList<TreeItemVo> treeItemVos = new ArrayList<>();
        //创建根节点
        Resource resource = Resource.builder().resourceNo(SuperConstant.ROOT_PARENT_ID).resourceName("智慧养老院").build();
        queryTheChildren(resource, list, treeItemVos);
        return TreeVo.builder().items(treeItemVos).build();
    }
    @Caching(evict = {
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_TREE,allEntries = true)
    })
    @Override
    public void updateResource(ResourceDto resourceDto) {
        Resource resource = BeanUtil.toBean(resourceDto, Resource.class);
        resourceMapper.updateById(resource);
    }

    @Transactional
    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_TREE,allEntries = true)
    })
    public void enableOrDisable(ResourceDto resourceDto) {
        Resource parentResource = resourceMapper.getById(resourceDto.getParentResourceNo());
        //判断父菜单是否禁用,不能启用子菜单
        if (parentResource != null) {
            if (parentResource.getDataState().equals(SuperConstant.DATA_STATE_1) && resourceDto.getDataState().equals(SuperConstant.DATA_STATE_0)) {
                throw new BaseException(BasicEnum.PARENT_MENU_DISABLE);
            }
        }
        //其他情况,启用禁用子菜单都会使子菜单的子菜单状态改变
        Resource resource = Resource.builder().parentResourceNo(NoProcessing.processString(resourceDto.getResourceNo())).build();
        List<ResourceVo> list = resourceMapper.list(resource);
        //先改变父菜单状态
        resourceMapper.enableOrDisable(resourceDto);
        //然后递归改变子菜单状态
        if (ObjectUtil.isNotEmpty(list)) {
            list.forEach(o -> {
                ResourceDto dto = ResourceDto.builder().dataState(resourceDto.getDataState()).resourceNo(o.getResourceNo()).build();
                // 递归调用
                enableOrDisable(dto);
            });
        }
    }

    @Override
    @Caching(evict = {
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_LIST,allEntries = true),
            @CacheEvict(cacheNames = RedisConstant.RESOURCE_TREE,allEntries = true)
    })
    public void delete(String resourceNo) {
        Resource resource = resourceMapper.getByResourceNo(resourceNo);
        //启用状态下的菜单不能删除
        if(SuperConstant.DATA_STATE_0.equals(resource.getDataState())){
            throw new BaseException(BasicEnum.ENABLED_CANNOT_DELETED);
        }
        //禁用有子级不能删除
        Resource res = Resource.builder().parentResourceNo(NoProcessing.processString(resourceNo)).build();
        List<ResourceVo> list = resourceMapper.list(res);
        if (ObjectUtil.isNotEmpty(list)) {
            throw new RuntimeException("菜单存在子级不能删除");
        }
        //TODO 禁用已经分配角色不能删除
        //其他情况可以删除
        resourceMapper.delete(resourceNo);

    }

    //递归方法
    private void queryTheChildren(Resource resource, List<ResourceVo> list, ArrayList<TreeItemVo> treeItemVos) {
        //根据当前节点创建TreeItemVo
        TreeItemVo itemVo = TreeItemVo.builder().id(resource.getResourceNo()).label(resource.getResourceName()).build();
        //搞定children,查询当前节点的子菜单,递归调用(父编号与当前节点的编号相同,即为当前节点的子菜单)
        List<ResourceVo> children = list.stream().filter(o -> o.getParentResourceNo().equals(resource.getResourceNo())).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(children)) {
            ArrayList<TreeItemVo> childTreeItemVos = new ArrayList<>();
            children.forEach(o -> {
                queryTheChildren(BeanUtil.toBean(o, Resource.class), list, childTreeItemVos);
            });
            itemVo.setChildren(childTreeItemVos);
        }
        treeItemVos.add(itemVo);
    }

}
